import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.signers.ECDSASigner;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.util.BigIntegers;

import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import org.bouncycastle.asn1.*;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.crypto.signers.ECDSASigner;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.util.encoders.Hex;

import java.io.*;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECPoint;
import java.security.MessageDigest;

public class SCTGenerator {

    // SCT版本定义
    private static final int SCT_VERSION_V1 = 0;
    
    // 日志ID长度（SHA-256哈希长度）
    private static final int LOG_ID_LENGTH = 32;
    
    // 签名算法标识
    private static final AlgorithmIdentifier ECDSA_SHA256 = new AlgorithmIdentifier(
        new ASN1ObjectIdentifier("1.2.840.10045.4.3.2")
    );

    // SCT数据结构
    public static class SignedCertificateTimestamp {
        public int version;
        public byte[] logId;
        public long timestamp;
        public byte[] extensions;
        public byte[] signature;
    }

    // 定义一个全局的 ArrayList<Boolean>
    private static ArrayList<Boolean> verifyArray = new ArrayList<>();

    // 生成密钥对
    public static AsymmetricCipherKeyPair generateKeyPair(String curveName) {
        try {
            ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec(curveName);
            ECDomainParameters domainParams = new ECDomainParameters(
                spec.getCurve(), spec.getG(), spec.getN(), spec.getH(), spec.getSeed());
            
            ECKeyPairGenerator generator = new ECKeyPairGenerator();
            generator.init(new ECKeyGenerationParameters(domainParams, new SecureRandom()));
            
            return generator.generateKeyPair();
        } catch (Exception e) {
            throw new RuntimeException("密钥对生成失败: " + e.getMessage(), e);
        }
    }

    // 生成SCT列表
    public static List<SignedCertificateTimestamp> generateSCTList(
            int count, byte[] logId, ECPrivateKeyParameters privateKey,ECPublicKeyParameters publicKey) {
        
        List<SignedCertificateTimestamp> sctList = new ArrayList<>();
        
        for (int i = 0; i < count; i++) {
            SignedCertificateTimestamp sct = new SignedCertificateTimestamp();
            sct.version = SCT_VERSION_V1;
            sct.logId = logId;
            sct.timestamp = System.currentTimeMillis(); // 转换为Unix时间戳
            sct.extensions = new byte[0]; // 无扩展
            
            // 构建待签名数据
            byte[] dataToSign = createDataToSign(sct);
            
            // 使用ECDSA签名
            sct.signature = generateSignature(dataToSign, privateKey,publicKey);
            
            sctList.add(sct);
        }
        
        return sctList;
    }

    // 创建待签名数据
    private static byte[] createDataToSign(SignedCertificateTimestamp sct) {
        try {
            // 构建TLV格式的签名数据
            // 结构: version(1) + log_id(32) + timestamp(8) + extensions(var)
            byte[] data = new byte[1 + LOG_ID_LENGTH + 8 + sct.extensions.length];
            int offset = 0;
            
            // 版本 (1字节)
            data[offset++] = (byte) sct.version;
            
            // 日志ID (32字节)
            System.arraycopy(sct.logId, 0, data, offset, LOG_ID_LENGTH);
            offset += LOG_ID_LENGTH;
            
            // 时间戳 (8字节, 大端序)
            long timestamp = sct.timestamp;
            for (int i = 7; i >= 0; i--) {
                data[offset++] = (byte) (timestamp >>> (i * 8));
            }
            
            // 扩展 (变长)
            System.arraycopy(sct.extensions, 0, data, offset, sct.extensions.length);
            
            return data;
        } catch (Exception e) {
            throw new RuntimeException("签名数据构建失败: " + e.getMessage(), e);
        }
    }

    // 生成ECDSA签名
    private static byte[] generateSignature(byte[] data, ECPrivateKeyParameters privateKey,ECPublicKeyParameters publicKey) {
        try {
            ECDSASigner signer = new ECDSASigner();
            signer.init(true, privateKey);
            
            // 计算数据哈希 (使用SHA-256)
            byte[] hash = java.security.MessageDigest.getInstance("SHA-256").digest(data);
            BigInteger[] signatureComponents = signer.generateSignature(hash);
            // 验证签名
            ECDSASigner verifier = new ECDSASigner();
            verifier.init(false, publicKey);
            boolean valid = verifier.verifySignature(hash, signatureComponents[0], signatureComponents[1]);
            verifyArray.add(valid);
            
            // 将签名编码为DER格式
            return encodeECDSASignature(signatureComponents[0], signatureComponents[1]);
        } catch (Exception e) {
            throw new RuntimeException("签名生成失败: " + e.getMessage(), e);
        }
    }

    // 编码ECDSA签名 (DER格式)
    private static byte[] encodeECDSASignature(BigInteger r, BigInteger s) {
        try {
            ASN1EncodableVector v = new ASN1EncodableVector();
            v.add(new ASN1Integer(r));
            v.add(new ASN1Integer(s));
            return new DERSequence(v).getEncoded();
        } catch (Exception e) {
            throw new RuntimeException("签名编码失败: " + e.getMessage(), e);
        }
    }

    // 将SCT列表写入二进制文件 (符合RFC 6962格式)
    public static void writeSCTListToBinaryFile(List<SignedCertificateTimestamp> sctList, String filename) 
        throws IOException {
        
        try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(filename))) {
            // 1. 首先计算整个SCT列表的总长度
            int totalSCTListLength = 0;
            List<byte[]> sctBytesList = new ArrayList<>();
            
            // 计算每个SCT的长度并序列化为字节数组
            for (SignedCertificateTimestamp sct : sctList) {
                // 计算单个SCT的长度
                int sctLength = 1 + LOG_ID_LENGTH + 8 + 2 + sct.extensions.length + 2 + 1 + sct.signature.length;
                
                // 创建字节数组缓冲区
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                DataOutputStream tempDos = new DataOutputStream(baos);
                
                // 写入SCT版本 (1字节)
                tempDos.writeByte(sct.version);
                
                // 写入日志ID (32字节)
                tempDos.write(sct.logId);
                
                // 写入时间戳 (8字节, 大端序)
                tempDos.writeLong(sct.timestamp);
                
                // 写入扩展长度和内容 (2字节长度 + 数据)
                tempDos.writeShort(sct.extensions.length);
                if (sct.extensions.length > 0) {
                    tempDos.write(sct.extensions);
                }

                byte[] my0403 = {0x04, 0x03};
                tempDos.write(my0403);

                // 写入签名长度和内容 (2字节长度 + DER签名)
                tempDos.writeShort(sct.signature.length);
                tempDos.write(sct.signature);
                
                // 获取SCT字节数组
                byte[] sctBytes = baos.toByteArray();
                sctBytesList.add(sctBytes);
                
                // 累加总长度 (SCT长度 + 2字节的长度前缀)
                totalSCTListLength += 2 + sctBytes.length;
            }
            
            // 2. 写入SCT列表的总长度 (2字节)
            byte[] my0482 = {(byte)0x04, (byte)0x82};
            dos.write(my0482);
            dos.writeShort(totalSCTListLength+2);
            dos.writeShort(totalSCTListLength);
            
            // 3. 写入每个SCT条目
            for (byte[] sctBytes : sctBytesList) {
                // 写入单个SCT的长度 (2字节)
                dos.writeShort(sctBytes.length);
                
                // 写入SCT数据
                dos.write(sctBytes);
            }
        }
        System.out.println("SCT列表已写入二进制文件: " + filename);
    }

    // 将SCT列表写入二进制文件 (符合RFC 6962格式)
    public static void writeSCTToBinaryFile(SignedCertificateTimestamp sct, String filename) 
        throws IOException {
        
        try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(filename))) {

                // 计算SCT总长度
                int totalLength = 1 + LOG_ID_LENGTH + 8 + 2 + sct.extensions.length + 2 + 1 + sct.signature.length;
                
                // 写入SCT长度 (2字节)
                dos.writeShort(totalLength);
                
                // 写入版本 (1字节)
                dos.writeByte(sct.version);
                
                // 写入日志ID (32字节)
                dos.write(sct.logId);
                
                // 写入时间戳 (8字节, 大端序)
                dos.writeLong(sct.timestamp);
                
                // 写入扩展长度和内容 (2字节长度 + 数据)
                dos.writeShort(sct.extensions.length);
                if (sct.extensions.length > 0) {
                    dos.write(sct.extensions);
                }

                byte[] my0403 = {0x04, 0x03};
                dos.write(my0403);

                // 写入签名长度和内容 (2字节长度 + DER签名)
                dos.writeShort(sct.signature.length);
                dos.write(sct.signature);

        }
        System.out.println("SCT列表已写入二进制文件: " + filename);
    }
    // 打印SCT信息
    public static void printSCT(SignedCertificateTimestamp sct,Integer index) {
        System.out.println("Signed Certificate Timestamp (SCT):");
        System.out.println("  Version: " + sct.version);
        System.out.println("  Log ID: " + Base64.getEncoder().encodeToString(sct.logId));
        System.out.println("  Timestamp: " + sct.timestamp + " (" + formatTimestamp(sct.timestamp) + ")");
        System.out.println("  Extensions: " + (sct.extensions.length > 0 ? 
                Base64.getEncoder().encodeToString(sct.extensions) : "None"));
        System.out.println("  Signature: " + Base64.getEncoder().encodeToString(sct.signature));
        System.out.println("  SignCheck: " + verifyArray.get(index));
        System.out.println();
    }
    
    // 格式化时间戳
    private static String formatTimestamp(long unixTimestamp) {
        return new java.util.Date(unixTimestamp).toString();
    }

    public static void main(String[] args) {
        // 1. 生成日志密钥对 (使用secp256r1曲线)
        AsymmetricCipherKeyPair keyPair = generateKeyPair("secp256r1");
        ECPrivateKeyParameters privateKey = (ECPrivateKeyParameters) keyPair.getPrivate();
        ECPublicKeyParameters publicKey = (ECPublicKeyParameters) keyPair.getPublic();
        ECPoint publicKeyPoint = publicKey.getQ();
        // 将公钥点编码为字节数组（压缩格式更高效）
        byte[] publicKeyBytes = publicKeyPoint.getEncoded(true);  // true 表示压缩格式
        // 2. 生成日志ID (通常是公钥的SHA-256哈希)
        byte[] logId = new byte[LOG_ID_LENGTH];
        byte[] sha256Hash = {};
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            sha256Hash = digest.digest(publicKeyBytes);
            logId = sha256Hash;
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (sha256Hash == null || sha256Hash.length == 0) {
            new SecureRandom().nextBytes(logId); // 当公钥sha256不存在就使用随机字符
        }

        
        
        // 3. 生成SCT列表 (3个SCT)
        List<SignedCertificateTimestamp> sctList = generateSCTList(3, logId, privateKey,publicKey);
        
        // 4. 打印结果
        System.out.println("Generated SCT List:");
        System.out.println("Log Public Key: " + 
                Base64.getEncoder().encodeToString(publicKey.getQ().getEncoded(false)));
        System.out.println("Log ID: " + Base64.getEncoder().encodeToString(logId));
        System.out.println();
        
        for (int i = 0; i < sctList.size(); i++) {
            System.out.println("SCT #" + (i + 1));
            printSCT(sctList.get(i),i);
            try{
                writeSCTToBinaryFile(sctList.get(i),"sct"+i+".sct");
            } catch (Exception e) {
                throw new RuntimeException("SCT写出文件失败: " + e.getMessage(), e);
            }
        }
        
        try{
            writeSCTListToBinaryFile(sctList,"sctlist.sct");
        } catch (Exception e) {
            throw new RuntimeException("SCTList写出文件失败: " + e.getMessage(), e);
        }
    }
}